package org.ala.tiktools.sharddb.mybatis.pager;


import org.ala.tiktools.mybatis.interfaces.AbstractOrderBy;
import org.ala.tiktools.mybatis.interfaces.IOrderBy;
import org.ala.tiktools.mybatis.pager.Pagement;
import org.ala.tiktools.mybatis.pager.Pager;
import org.ala.tiktools.sharddb.exception.ShardDBRuntimeException;
import org.ala.tiktools.sharddb.mybatis.executor.ShardExecutor;
import org.ala.tiktools.sharddb.mybatis.executor.ShardNoTxExecutor;
import org.ala.tiktools.sharddb.mybatis.interceptor.Shard;
import org.ala.tiktools.sharddb.mybatis.pager.after_pager.ShardAfterPager;
import org.ala.tiktools.sharddb.mybatis.pager.after_pager.ShardAfterPagerHandler;
import org.ala.tiktools.sharddb.mybatis.pager.parameter.CountMethod;
import org.ala.tiktools.sharddb.mybatis.pager.parameter.DataMethod;
import org.ala.tiktools.sharddb.mybatis.pager.parameter.ShardPagerMethodHandler;
import org.ala.tiktools.sharddb.mybatis.pager.parameter.ShardPagerParameter;
import org.ala.tiktools.sharddb.mybatis.pager.with_order.ShardPagerWithOrderByHandler;
import org.ala.tiktools.sharddb.mybatis.pager.without_order.ShardPagerWithoutOrderByHandler;
import org.ala.tiktools.sharddb.mybatis.router.ShardInfo;
import org.ala.tiktools.tools.CachingKVTools;
import org.ala.tiktools.tools.kv.KV;
import org.ala.tiktools.tools.kv.Maps;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 分库分表模式下的分页
 * <p>  用"无跳页"的模式跳到最终需要的数据页
 *
 * @author ala
 * @date 2025-02-28 09:58
 */
public class ShardPagerHandler {
    /**
     *  方法查找处理器
     *  <p> 查找method和
     */
    protected ShardPagerMethodHandler shardPagerMethodHandler = new ShardPagerMethodHandler();
    /**
     *  不含排序的分页
     */
    protected ShardPagerWithoutOrderByHandler shardPagerWithoutOrderByHandler = new ShardPagerWithoutOrderByHandler();
    /**
     *  含排序的分页
     */
    protected ShardPagerWithOrderByHandler shardPagerWithOrderByHandler = new ShardPagerWithOrderByHandler();
    /**
     *  after_pager分页方式处理器
     */
    protected ShardAfterPagerHandler shardAfterPagerHandler = new ShardAfterPagerHandler();


    /**
     *  进到这里的都是有多库多表的情况
     */
    public Map<ShardInfo, ShardExecutor.Result> doPage(Shard anno, Pagement pagement, ThreadPoolExecutor threadPool, Object proxy, Method method, Object[] args, Map<ShardInfo, Object[]> shardInfoMap) {
        //  取IOrderBy的下标
        Integer orderByIdx = orderByIndex.get(method);
        AbstractOrderBy orderBy = null;
        if (orderByIdx != null && orderByIdx >= 0) {
            orderBy = (AbstractOrderBy) args[orderByIdx];
        }
        //  取pager的下标
        Integer pagerIdx = pagerIndex.get(method);
        if (pagerIdx == null || pagerIdx < 0) {
            throw new ShardDBRuntimeException(String.format("分页方法无法找到有效的Pager参数 method:%s class:%s", method.getName(), method.getDeclaringClass().getSimpleName()));
        }
        Pager pager = (Pager) args[pagerIdx];
        //  将 shardInfoMap 中的每一个orderBy和Pager改成同一个对象，方便下面修改统一参数
        for (Object[] value : shardInfoMap.values()) {
            if (orderByIdx != null && orderByIdx >= 0) {
                value[orderByIdx] = orderBy;
            }
            value[pagerIdx] = pager;
        }

        //  包装DataMethod和CountMethod
        DataMethod dm = shardPagerMethodHandler.dataMethod(proxy, method, shardInfoMap);
        CountMethod cm = shardPagerMethodHandler.countMethod(pagement.count(), dm);

        //  封装分页查询参数
        ShardPagerParameter parameter = ShardPagerParameter.build(anno, threadPool, pagerIdx, pager, orderByIdx, orderBy, 0, cm, dm);

        //  如果是afterPage模式，直接执行
        if (pager instanceof ShardAfterPager) {
            return shardAfterPagerHandler.doAfterPager(parameter);
        }

        //  如果不含orderBy
        if (orderBy == null) {
            return shardPagerWithoutOrderByHandler.doPageWithoutOrderBy(parameter);
        } else {
            return shardPagerWithOrderByHandler.doPageWithOrderBy(parameter);
        }
    }





    /**
     *  pager的下标
     */
    protected CachingKVTools<Method, Integer> pagerIndex = new CachingKVTools<>(-1, m -> {
        for (int i = 0; i < m.getParameters().length; i++) {
            if (Pager.class.isAssignableFrom(m.getParameters()[i].getType())) {
                return i;
            }
        }
        return null;
    });
    /**
     *  IOrderBy的下标
     */
    protected CachingKVTools<Method, Integer> orderByIndex = new CachingKVTools<>(-1, m -> {
        for (int i = 0; i < m.getParameters().length; i++) {
            if (IOrderBy.class.isAssignableFrom(m.getParameters()[i].getType())) {
                return i;
            }
        }
        return null;
    });
    protected IOrderBy getOrderBy(Method method, Object[] args) {
        Integer idx = orderByIndex.get(method);
        if (idx == null || idx < 0) {return null;}
        return (IOrderBy) args[idx];
    }


    protected Map<String, Method> countMethodMapper = new HashMap<>();
    /**
     *  Method与CountMethod之间映射
     */
    protected Method getCountMethod(Method method, String countName) {
        String name = String.format("%s_%s", method.getDeclaringClass().getName(), countName);
        Method countMethod = countMethodMapper.get(name);
        if (countMethod == null) {
            synchronized (name.intern()) {
                countMethod = countMethodMapper.get(name);
                if (countMethod == null) {
                    countMethod = ClassUtils.getMethod(method.getDeclaringClass(), countName, method.getParameterTypes());
                    countMethodMapper.put(name, countMethod);
                }
            }
        }
        return countMethod;
    }
}
